﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RobotParser
{
    class RobotParser : BaseParser
    {
        public RobotParser(RobotScanner scanner)
        {
            this.scanner = scanner;
        }
     
        public bool Parse()
        {
            Reset();

            bool res = ParseProgram();
            if (!res)
            {
                ++counter;
            }

            return res;
        }

        private bool ParseProgram()
        {
            return ParseToken(TokenType.START) && ParseRule1() && ParseToken(TokenType.STOP);
        }

        private bool ParseRule1()
        {
            if (IsNextRule2())
            {
                bool res = ParseRule2();
                if (res && IsNextRule4())
                {
                    return ParseRule4() && ParseRule2();
                }

                return res;
            }

            return ParseRule4() && ParseRule2() && ParseRule1();
        }

        private bool IsNextRule2()
        {
            return ParseRule3(true) || ParseRule5(true);
        }

        private bool IsNextRule4()
        {
            return ParseRule4(true);
        }

        private bool ParseRule2()
        {
            if (IsNextRule3())
            {
                bool res = ParseRule3();
                if (res && IsNextRule5())
                {
                    return ParseRule5() && ParseRule3();
                }

                return res;
            }

            return ParseRule5() && ParseRule3() && ParseRule2();
        }

        private bool IsNextRule3()
        {
            return ParseRule3(true);
        }

        private bool IsNextRule5()
        {
            return ParseRule5(true);
        }

        private bool ParseRule4(bool scanOnly = false)
        {
            if (scanOnly)
            {
                return CheckNextTokenIs(TokenType.STEP_LPAREN);
            }

            return ParseToken(TokenType.STEP_LPAREN) && ParseToken(TokenType.INTEGER) && ParseToken(TokenType.RPAREN);
        }

        private bool ParseRule5(bool scanOnly = false)
        {
            if (scanOnly)
            {
                return CheckNextTokenIs(TokenType.TURN_HEAD);
            }

            return ParseToken(TokenType.TURN_HEAD);
        }

        private bool ParseRule3(bool scanOnly = false)
        {
            if (scanOnly)
            {
                switch (GetForwardToken().Type)
                {
                    case TokenType.LEFT:
                    case TokenType.RIGHT:
                    case TokenType.HANDS_UP:
                    case TokenType.ON_45:
                        return true;
                    default:
                        return false;
                }
            }

            switch (GetForwardToken().Type)
            {
                case TokenType.LEFT: return ParseToken(TokenType.LEFT);
                case TokenType.RIGHT: return ParseToken(TokenType.RIGHT);
                case TokenType.HANDS_UP: return ParseToken(TokenType.HANDS_UP) && ParseRule1() && ParseToken(TokenType.HANDS_DOWN);
                case TokenType.ON_45: return ParseToken(TokenType.ON_45) && ParseRule3();
                default: return false;
            }
        }
    }
}
